#pragma once
#include <sys/select.h>
#include "Common.hpp"
#include "Socket.hpp"
using namespace SocketModule;

class SelectServer : public NoCopy
{
private:
    void ListenSocketHandler()
    {
        std::shared_ptr<TCPConnectSocket> connect_socket = _listen_socket->Accept();
        int connect_sockfd = connect_socket->SockFd();
        _fds[connect_sockfd] = connect_socket;
    }
    void ConnectSocketHandler(int fd)
    {
        std::string message;
        int n = _fds[fd]->Receive(message);
        if(n > 0)
        {
            // 正常收到消息
            std::cout << "Client[" << _fds[fd]->Addr().Info() << "] say# " << message << std::endl;
        }
        else if(n == 0)
        {
            // 客户端断开连接
            LOG(LogLevel::INFO) << "Client[" << _fds[fd]->Addr().Info() << "]已断开连接...";
            _fds[fd] = _default_socket_ptr;
        }
        else
        {
            // 出错
            LOG(LogLevel::ERROR) << "Receive: 接收Client[" << _fds[fd]->Addr().Info() << "]的数据失败! ";
        }
    }
    void Dispatch(fd_set *readfds)
    {
        for (int fd = 0; fd < _fds.size(); fd++)
        {
            if (!_fds[fd] || !FD_ISSET(fd, readfds))
                continue;
            if (fd == _listen_socket->SockFd())
            {
                // 监听套接字
                ListenSocketHandler();
            }
            else
            {
                // 连接套接字
                ConnectSocketHandler(fd);
            }
        }
    }

public:
    SelectServer(in_port_t port)
        : _isrunning(false)
        , _listen_socket(std::make_shared<TCPListenSocket>(port))
        , _fds(sizeof(fd_set) * 8, _default_socket_ptr)
    {
        int listen_sockfd = _listen_socket->SockFd();
        _fds[listen_sockfd] = _listen_socket;
    }
    void Run()
    {
        _isrunning = true;
        while (_isrunning)
        {
            fd_set readfds;
            FD_ZERO(&readfds);
            int max_fd = _listen_socket->SockFd();
            for (int fd = 0; fd < _fds.size(); fd++)
            {
                if (_fds[fd])
                {
                    FD_SET(fd, &readfds);
                    max_fd = std::max(max_fd, fd);
                }
            }
            struct timeval timeout = {10, 0};
            int n = select(max_fd + 1, &readfds, nullptr, nullptr, &timeout);
            if (n > 0)
            {
                // 有事件就绪
                LOG(LogLevel::INFO) << "有事件就绪, 即将处理...";
                Dispatch(&readfds);
            }
            else if (n == 0)
            {
                // 超时
                LOG(LogLevel::DEBUG) << "超时处理...";
            }
            else
            {
                // 出错
                LOG(LogLevel::FATAL) << "select: " << strerror(errno);
                break;
            }
        }
        _isrunning = false;
    }
    ~SelectServer() {}

private:
    bool _isrunning;
    std::shared_ptr<TCPListenSocket> _listen_socket; // 监听套接字
    std::vector<std::shared_ptr<Socket>> _fds;       // 需要select等待的套接字
    static const std::shared_ptr<Socket> _default_socket_ptr;
};
const std::shared_ptr<Socket> SelectServer::_default_socket_ptr = nullptr;